package mobi.yuanshen.aspect;

import com.alibaba.fastjson2.JSONObject;
import io.jsonwebtoken.Claims;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import mobi.yuanshen.mapper.OperateLogMapper;
import mobi.yuanshen.pojo.OperateLog;
import mobi.yuanshen.utils.JwtUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.Arrays;

@Component
@Aspect
@Slf4j
public class LogAspect {

    @Autowired
    HttpServletRequest request;// 直接从IOC容器中获取HttpServletRequest对象

    @Autowired
    JwtUtils jwtUtils;

    @Autowired
    private OperateLogMapper logMapper;

    @Pointcut("@annotation(mobi.yuanshen.anno.Log)")
    public void pt(){}

    @Around("pt()")
    public Object recordLog (ProceedingJoinPoint joinPoint) throws Throwable {

        String jwt = request.getHeader("token");
        Claims claims = jwtUtils.parseJWT(jwt);
        OperateLog operateLog = new OperateLog(); // 创建实体类对象

        operateLog.setId(null); // 设置日志id为null，因为主键自增
        operateLog.setOperateUser((Integer) claims.get("id")); // 设置操作人id
        operateLog.setOperateTime(LocalDateTime.now()); // 设置操作时间
        operateLog.setClassName(joinPoint.getTarget().getClass().getName());// 设置类名
        operateLog.setMethodName(joinPoint.getSignature().getName());// 设置操作方法名

        Object[] args = joinPoint.getArgs();
        StringBuilder sb = new StringBuilder("[");
        for (Object arg : args) { // 解决数组参数无法正确转换成字符串的问题
            if (arg instanceof Object[]) {
                sb.append(Arrays.toString((Object[]) arg));
            }else {
                sb.append(arg.toString());
            }
        }
        sb.append("]");
        operateLog.setMethodParams(sb.toString()); // 设置操作方法参数

        long beginTime = System.currentTimeMillis();// 执行原始方法的开始时间
        Object res = joinPoint.proceed(); // 执行原始方法

        operateLog.setCostTime(System.currentTimeMillis() - beginTime); // 设置操作耗时
        operateLog.setReturnValue(JSONObject.toJSONString(res)); // 设置方法返回值
        logMapper.insert(operateLog); // 提交数据库
        return res;
    }
}
